use crate::lib_cgroup::{cgroup_limit_mem, cgroup_limit_mem_rm};
use crate::lib_init_web::init_web;
use crate::lib_ns_ctrl_c::ns_ctrl_c;
use crate::lib_ns_rootfs::{ns_fs_proc_mount, ns_rootfs_setup};
use crate::lib_ns_ugid_map::map_uid_gid;
use libc::{__errno_location, c_char, c_int, clone, close, dup2, execlp, exit, fread, free, malloc, open, pid_t, pipe, printf, read, sleep, strerror, strlen, wait, waitpid, write, CLONE_FILES, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUSER, CLONE_NEWUTS, O_CREAT, O_TRUNC, O_WRONLY, SIGCHLD};
use std::env::{args, args_os};

use std::ffi::{c_void, CStr, CString};
use std::io::stderr;
use std::ptr::{null, null_mut};

pub fn namespace_d(execute_able: *const c_char) {
    ///CLONE_NEWUTS: 创建新的 UTS 命名空间（主机名和域名）。
    ///
    /// CLONE_NEWIPC: 创建新的 IPC 命名空间（进程间通信）。
    ///
    /// CLONE_NEWPID: 创建新的 PID 命名空间（进程 ID）。
    ///
    /// CLONE_NEWNS: 创建新的挂载命名空间（文件系统挂载点）。
    ///
    /// CLONE_NEWNET: 创建新的网络命名空间（网络设备、端口等）。
    ///
    /// CLONE_NEWUSER: 创建新的用户命名空间（用户和组 ID）。
    let flags =
        CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWUSER ;
    // let flags = CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET;

    unsafe {
        let (pid, stack) = create_new_ns_proc(flags | SIGCHLD, execute_able);

        ns_init(pid);
        init_web(pid);
        println!("后台模式运行容器");
        exit(0);
    };
}

pub unsafe fn create_new_ns_proc(
    flags: c_int,
    execute_able: *const c_char,
) -> (c_int, *mut c_void) {
    //构建父子进程通讯管道
    let mut fd = [0; 2];
    if pipe(fd.as_mut_ptr()) < 0 {
        printf(c"%s".as_ptr(), strerror(*__errno_location()));
        exit(3)
    };
    //分配命名空间堆大小
    let stack_size = 1024 * 1024 * 100; //100MB
    let stack = malloc(stack_size);
    if stack.is_null() {
        println!("[error] Failed to allocate stack");
        exit(1);
    }
    //创建命名空间
    let arg = fd.as_mut_ptr() as *mut c_void;
    let pid = clone(child_func, stack.add(stack_size), flags, arg);
    println!("[info] Create new process pid {}", pid);
    //传输可执行命令
    write(
        fd[1],
        execute_able as *const c_void,
        strlen(execute_able) + 1,
    );
    close(fd[0]);
    close(fd[1]);

    (pid, stack)
}

pub extern "C" fn child_func(args: *mut c_void) -> c_int {
    unsafe {
        //root mount设置
        ns_fs_setup();

        //获取父进程pipe传入的参数
        let fd = args as *mut c_int;
        let pipe_read = fd.offset(0).read();
        let pipe_write = fd.offset(1).read();

        //关闭写管道
        close(pipe_write);



        let mut execute_able = [0; 1024];
        let mut execute_able_ptr = execute_able.as_mut_ptr();
        let mut read_count = 0;
        while true {
            let count = read(
                pipe_read,
                execute_able_ptr as *mut c_void,
                execute_able.len(),
            );
            if count == 0 {
                //父进程已关闭管道
                break;
            }
            read_count += count;
            execute_able_ptr = execute_able_ptr.offset(count as isize);
        }

        //关闭子进程管道
        close(pipe_read);

        //可执行命令
        let execute_able_ptr = execute_able[0..read_count as usize].as_ptr();
        let execute_able = CStr::from_ptr(execute_able_ptr).as_ptr();

        //重定位输入输出
        let std_out = open(c"/.log".as_ptr(), O_WRONLY | O_CREAT | O_TRUNC, 0777);
        if std_out<0 {
            printf(c"%s\n".as_ptr(), strerror(*__errno_location()));
            exit(3);
        }
        if dup2(std_out,1)<0 {
            printf(c"%s\n".as_ptr(), strerror(*__errno_location()));
            exit(3);
        }
        if dup2(std_out,2)<0 {
            printf(c"%s\n".as_ptr(), strerror(*__errno_location()));
            exit(3);
        }
        close(0);

        //执行可执行命令
        let i = execlp(execute_able, execute_able, null::<c_void>());
        printf(c"%s\n".as_ptr(), execute_able);
        printf(c"%s\n".as_ptr(),strerror(*__errno_location()));
        println!("[error] Failed to exec new process {}", i);
        exit(i);
        i

    }
}
pub fn ns_init(pid_t: pid_t) {
    ns_set_user(pid_t);
    ns_set_cgroup(pid_t);
    ns_set_ctrl_c(pid_t);
}

pub fn ns_set_user(pid: pid_t) {
    //make CLONE_NEWUSER as root
    match map_uid_gid(pid) {
        Ok(_) => {}
        Err(e) => {
            println!("{}", e);
        }
    }
}
pub fn ns_set_cgroup(pid: pid_t) {
    match cgroup_limit_mem(pid) {
        Ok(_) => {}
        Err(e) => {
            println!("{}", e);
        }
    }
}
pub fn ns_set_ctrl_c(pid: pid_t) {
    match ns_ctrl_c() {
        Ok(_) => {}
        Err(e) => {
            println!("{}", e);
        }
    }
}

pub fn ns_fs_setup() {
    match ns_rootfs_setup() {
        Ok(_) => {}
        Err(e) => {
            println!("{}", e);
        }
    }
    // match ns_fs_proc_mount() {
    //     Ok(_) => {}
    //     Err(e) => { println!("{}", e); }
    // }
}
fn clean(pid: c_int) {
    match cgroup_limit_mem_rm() {
        Ok(_) => {}
        Err(e) => {
            println!("{}", e);
        }
    }
}
